#pragma once

#include "DBManager/Common/TemplateFunction.h"
/*
 * Copyright (c) 2025, 大连理工大学 (Dalian University of Technology)
 *
 * Licensed under the Mulan PSL v2.
 * You can use this file according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of the License at
 *
 *     http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. SEE THE MULAN PSL v2
 * FOR MORE DETAILS.
 */

/**
 * @brief 注册 HDF5 数据库仓库创建和删除函数
 *
 * 使用此宏可以生成用于创建和删除特定 HDF5 数据库仓库的函数，并将这些函数注册到 HDF5 数据库管理器中。
 *
 * @param RepositoryName 仓库类的名称
 */

#define HDF5_REG_REPOSITORY(RepositoryName)                                                                                           \
    void* New##RepositoryName (SG::DBManager::HDF5Database& dataBase)                                                                 \
    {                                                                                                                                 \
        auto resp = new SG::DBManager::HDF5::RepositoryName (dataBase);                                                               \
        resp->InitialDatasetInfo ();                                                                                                  \
        resp->InitDataset ();                                                                                                         \
        return reinterpret_cast<void*> (resp);                                                                                        \
    };                                                                                                                                \
                                                                                                                                      \
    void Del##RepositoryName (void* Rep)                                                                                              \
    {                                                                                                                                 \
        auto resp = static_cast<SG::DBManager::HDF5::RepositoryName*> (Rep);                                                          \
        if (resp->GetMainCache ().m_writeStorage.size () > 0 || resp->IsExistData (SG::DBManager::HDF5::RepositoryName::MainDataset)) \
        {                                                                                                                             \
            if (resp->GetMainCache ().m_writeStorage.size () > 0)                                                                     \
                resp->DumpWriteCahce ();                                                                                              \
            resp->SortData ();                                                                                                        \
        }                                                                                                                             \
        delete resp;                                                                                                                  \
    };                                                                                                                                \
                                                                                                                                      \
    bool HDF5##RepositoryName##FunPReg =                                                                                              \
        SG::DBManager::HDF5Database::RegRepoFunP (typeid (I##RepositoryName).hash_code (), { New##RepositoryName, Del##RepositoryName });

/**
 * @brief 注册 HDF5 数据库 Result仓库创建和删除函数
 *
 * 使用此宏可以生成用于创建和删除特定 HDF5 数据库仓库的函数，并将这些函数注册到 HDF5 数据库管理器中。
 *
 * @param RepositoryName 仓库类的名称
 */
#define HDF5_REG_NO_SORT_REPOSITORY(RepositoryName)                          \
    void* New##RepositoryName (SG::DBManager::HDF5Database& dataBase)        \
    {                                                                        \
        auto resp = new SG::DBManager::HDF5::RepositoryName (dataBase);      \
        resp->InitialDatasetInfo ();                                         \
        resp->InitDataset ();                                                \
        return reinterpret_cast<void*> (resp);                               \
    };                                                                       \
                                                                             \
    void Del##RepositoryName (void* Rep)                                     \
    {                                                                        \
        auto resp = static_cast<SG::DBManager::HDF5::RepositoryName*> (Rep); \
        delete resp;                                                         \
    };                                                                       \
                                                                             \
    bool HDF5##RepositoryName##FunPReg =                                     \
        SG::DBManager::HDF5Database::RegRepoFunP (typeid (I##RepositoryName).hash_code (), { New##RepositoryName, Del##RepositoryName });

/**
 * @brief 从主表数据加载相关的从表数据
 *
 * 使用此宏根据主表中的数据加载相应的从表数据。
 *
 * @param IDENTITYData 主表数据变量名称
 * @param PosField 主表中描述起始位置的成员变量名称
 * @param LenField 主表中描述长度的成员变量名称
 * @param SecondaryKey 从表的枚举值
 * @param SecondaryData 从表数据的变量名称
 */

#define LoadSecondaryMetadata(IDENTITYData, PosField, LenField, SecondaryKey, SecondaryData)                       \
                                                                                                                   \
    if (!IDENTITYData.empty ())                                                                                    \
    {                                                                                                              \
        const std::size_t beginIndex = IDENTITYData.front ().PosField;                                             \
        const std::size_t length     = IDENTITYData.back ().PosField + IDENTITYData.back ().LenField - beginIndex; \
        GetDataset (SecondaryKey).select ({ beginIndex }, { length }).read (SecondaryData);                        \
    }

#define HDF5_REG_ELEMENT_REPOSITORY(RepositoryName)                                                                                       \
    void* New##RepositoryName (SG::DBManager::HDF5Database& dataBase)                                                                     \
    {                                                                                                                                     \
        auto resp = new SG::DBManager::HDF5::RepositoryName (dataBase);                                                                   \
        resp->InitialDatasetInfo ();                                                                                                      \
        resp->InitDataset ();                                                                                                             \
        return reinterpret_cast<void*> (resp);                                                                                            \
    };                                                                                                                                    \
                                                                                                                                          \
    void Del##RepositoryName (void* Rep)                                                                                                  \
    {                                                                                                                                     \
        auto resp = static_cast<SG::DBManager::HDF5::RepositoryName*> (Rep);                                                              \
        if (resp->GetMainCache ().m_writeStorage.size () > 0 || resp->IsExistData (SG::DBManager::HDF5::RepositoryName::MainDataset))     \
        {                                                                                                                                 \
            if (resp->GetMainCache ().m_writeStorage.size () > 0)                                                                         \
                resp->DumpWriteCahce ();                                                                                                  \
            resp->SortData ();                                                                                                            \
        }                                                                                                                                 \
        delete resp;                                                                                                                      \
    };                                                                                                                                    \
                                                                                                                                          \
    bool HDF5##RepositoryName##FunPReg =                                                                                                  \
        SG::DBManager::HDF5Database::RegRepoFunP (typeid (I##RepositoryName).hash_code (), { New##RepositoryName, Del##RepositoryName }); \
                                                                                                                                          \
    bool HDF5##RepositoryName##P2E = SG::DBManager::RegisterP2E<SG::DBManager::HDF5::RepositoryName::DataType, I##RepositoryName> ();     \
    bool HDF5##RepositoryName##GEN = SG::DBManager::HDF5Hub::ConnectGetElementNodes (                                                     \
        I##RepositoryName::GetType (), SG::DBManager::AssembleElementNodes<I##RepositoryName>);                                           \
    bool HDF5##RepositoryName##INITELEM = SG::DBManager::HDF5Hub::ConnectInitElementReposMethods (                                        \
        I##RepositoryName::GetType (), [] (SG::DBManager::IDatabase* db) { db->GetRepository<I##RepositoryName> (); });                   \
                                                                                                                                          \
    template <>                                                                                                                           \
    DBManager_DECLSPEC SG::DataStructure::Common::Status SG::DBManager::DataOperate::Add (                                                \
        SG::DBManager::HDF5::RepositoryName::DataType& data)                                                                              \
    {                                                                                                                                     \
        return m_database->GetRepository<I##RepositoryName> ()->Add (data);                                                               \
    };                                                                                                                                    \
                                                                                                                                          \
    template <>                                                                                                                           \
    DBManager_DECLSPEC SG::DataStructure::Common::Status SG::DBManager::DataOperate::MultiAdd (                                           \
        SG::DBManager::HDF5::RepositoryName::DataType& data)                                                                              \
    {                                                                                                                                     \
        return m_database->GetRepository<I##RepositoryName> ()->Add (data);                                                               \
    };                                                                                                                                    \
                                                                                                                                          \
    template <>                                                                                                                           \
    DBManager_DECLSPEC SG::DataStructure::Common::Status SG::DBManager::DataOperate::FindByIndex (                                        \
        std::size_t index, SG::DBManager::HDF5::RepositoryName::DataType& entity)                                                         \
    {                                                                                                                                     \
        return m_database->GetRepository<I##RepositoryName> ()->FindByIndex (index, entity);                                              \
    };                                                                                                                                    \
                                                                                                                                          \
    template <>                                                                                                                           \
    DBManager_DECLSPEC SG::DataStructure::Common::Status SG::DBManager::DataOperate::FindById (                                           \
        SG::DataStructure::Common::Id id, SG::DBManager::HDF5::RepositoryName::DataType& entity)                                          \
    {                                                                                                                                     \
        return m_database->GetRepository<I##RepositoryName> ()->FindById (id, entity);                                                    \
    };                                                                                                                                    \
                                                                                                                                          \
    template <>                                                                                                                           \
    DBManager_DECLSPEC std::size_t SG::DBManager::DataOperate::Size<SG::DBManager::HDF5::RepositoryName::DataType> ()                     \
    {                                                                                                                                     \
        return m_database->GetRepository<I##RepositoryName> ()->Size ();                                                                  \
    };                                                                                                                                    \
                                                                                                                                          \
    template <>                                                                                                                           \
    DBManager_DECLSPEC std::vector<SG::DataStructure::Common::Id>                                                                         \
                       SG::DBManager::DataOperate::GetAllId<SG::DBManager::HDF5::RepositoryName::DataType> ()                             \
    {                                                                                                                                     \
        return m_database->GetRepository<I##RepositoryName> ()->GetAllId ();                                                              \
    };                                                                                                                                    \
                                                                                                                                          \
    template <>                                                                                                                           \
    DBManager_DECLSPEC std::vector<SG::DBManager::HDF5::RepositoryName::DataType>                                                         \
                       SG::DBManager::DataOperate::GetAllData<SG::DBManager::HDF5::RepositoryName::DataType> ()                           \
    {                                                                                                                                     \
        return m_database->GetRepository<I##RepositoryName> ()->GetAllData ();                                                            \
    };                                                                                                                                    \
                                                                                                                                          \
    template <>                                                                                                                           \
    DBManager_DECLSPEC std::size_t SG::DBManager::DataOperate::Count<SG::DBManager::HDF5::RepositoryName::DataType> (                     \
        SG::DataStructure::Common::Id id)                                                                                                 \
    {                                                                                                                                     \
        return m_database->GetRepository<I##RepositoryName> ()->Count (id);                                                               \
    };                                                                                                                                    \
                                                                                                                                          \
    template <>                                                                                                                           \
    DBManager_DECLSPEC std::size_t SG::DBManager::DataOperate::GetElementNodeSize<SG::DBManager::HDF5::RepositoryName::DataType> ()       \
    {                                                                                                                                     \
        return I##RepositoryName::GetCurrentTypeNodeSize ();                                                                              \
    };
